<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>星轨制作器</title>
        <style>
            canvas{
                border: black 1px solid;
            }
        </style>
    </head>
    <body>
    <form>
        <input type="file" id="input" accept="video/mp4" onclick="LoadVideo()"><br>
        <label>
            Debug Mode <input type="checkbox" id="debug" checked><br>
        </label>
        <label>
            视频大小不予改变 <br>
        </label>
        <label >
            视频帧率: <input type="number" step="1" max="60" min="24" value="25" id="fps">
        </label>
        <label >
            视频码率(mbps): <input type="number" step="1" max="50" min="2" value="20" id="bits">
        </label>
        <label>
            拖尾量: <input type="number" step="1" min="1" max="100" value="25" id="delay">
        </label>
        <label>
            拖尾衰减: <input type="number" step="0.01" min="0" max="1" value="0.02" id="fade">
        </label>
    </form>
    <button onclick="OnClick()" id="button" disabled>开始渲染</button>
    <div id="message"><span>Message:</span><span id="msgSpan"></span></div>
    </body>
<script>
    let setting;
    let video;

    let message = document.getElementById("msgSpan");
    let msgString = "";
    let msgTimer = setInterval(function (){
        message.innerHTML = msgString;
    },100);

    let frames = [];

    let resultList=[];
    let resultCnv;
    let resultCtx;

    let recorder;
    let chunks = [];

    let blobOption = {type:"video/mp4"};
    let recorderOption = {
        mimeType : "video/mp4",
        videoBitsPerSecond: 20000000
    }
    let type = ".mp4";

    /*let blobOption = {type:"video/webm"};
    let recorderOption = {
        mimeType : "video/webm",
        videoBitsPerSecond: 20000000
    }
    let type = ".webm";*/

    function LoadVideo(){
        //初始化video
        let btn = document.getElementById("button");
        btn.disabled = true;
        let input = document.getElementById("input");
        input.oninput = function (){
            Log("已选择文件");
            try{
                video = document.createElement("video");
                video.src = URL.createObjectURL(input.files[0]);
                video.alt = input.files[0].name;
                video.oncanplay = function (){
                    Log("视频加载完成");
                    btn.disabled = false;
                }
            }catch (e){
                alert("请选择正确的文件");
            }
        }
    }

    function Init(){

        //获取表单
        setting = {
            fps:parseInt(document.getElementById("fps").value) ,
            width:video.videoWidth,
            height:video.videoHeight,
            delay:parseInt(document.getElementById("delay").value),
            fade:parseFloat(document.getElementById("fade").value),
            bits:parseInt(document.getElementById("bits").value),
            debug:(document.getElementById("debug").checked),
            name:video.alt.split(".")[0]
        }
        console.log(setting);

        Show(video);

        //初始化录制器
        resultCnv = document.createElement("canvas");
        resultCtx = resultCnv.getContext("2d");
        resultCnv.width = setting.width;
        resultCnv.height = setting.height;
        Show(resultCnv);

        recorderOption.videoBitsPerSecond= setting.bits*1000000;
        recorder = new MediaRecorder(resultCnv.captureStream(setting.fps),recorderOption);
        chunks = [];
        recorder.ondataavailable = function (e){
            Log("录制结束，开始生成文件");
            chunks.push(e.data);
            console.log(chunks);
            setTimeout(function (){
                //在这里执行最终生成文件___________________________________________
                DownLoad(chunks);
            },2000);
        }
        console.log(recorderOption);
    }

    function GetFrames(){
        let cnv = document.createElement("canvas");
        let ctx = cnv.getContext("2d",{willReadFrequently:true});
        cnv.width = setting.width;
        cnv.height = setting.height;
        Show(cnv);

        video.play();

        let currentTime = new Date().getTime();
        let timer = setInterval(function (){
            ctx.drawImage(video,0,0);
            frames.push(ctx.getImageData(0,0,setting.width,setting.height));
        },1000/setting.fps);
        video.onended = function (){
            clearInterval(timer);
            Log("视频播放完毕");
            Log("视频帧长度："+frames.length);
            Log("视频长度："+(new Date().getTime()-currentTime)/1000+"s");
            Log("开始渲染，请等待");
            //开始进行渲染
            setTimeout(function (){
                //在这里进行渲染_________________________________________________
                Render();
            },2000);
        }
    }

    function Render(){
        Log("开始渲染");
        //正式对视频进行渲染

        //建立延时缓冲Canvas队列
        let cnvList = [];
        let dataList = [];
        resultList = [];
        framesLength = frames.length;

        let combineCnv = document.createElement("canvas");
        let combineCtx = combineCnv.getContext("2d",{willReadFrequently:true});
        combineCnv.width = setting.width;
        combineCnv.height = setting.height;
        combineCtx.globalCompositeOperation="lighten";
        Show(combineCnv);

        for(i=0;i<setting.delay;i++){
            let cnv = document.createElement("canvas");
            let ctx = cnv.getContext("2d",{willReadFrequently:true});
            cnv.width =  setting.width;
            cnv.height = setting.height;
            Show(cnv);
            cnvList.push({cnv:cnv,ctx:ctx});
        }
        Log("完成加载cnvList:"+cnvList.length);

        //开始渲染
        for(i=0;i<framesLength;i++){

            //重置combine
            combineCtx.clearRect(0,0,setting.width,setting.height);

            //console.log("渲染帧："+i+"_________________________________________");
            Log("渲染帧："+i);

            //获取参加渲染的信息
            dataList.unshift(frames.shift());
            if(dataList.length>setting.delay){
                dataList.pop();
            }

            //在每个Canvas上绘制贴图
            for(j=0;j<dataList.length;j++){

                let fadeRate = 1- j*setting.fade;

                if(fadeRate<=0)break;

                console.log("*渲染子帧："+j+"  fadeRate:"+fadeRate);

                let ctx = cnvList[j].ctx;
                ctx.globalAlpha= 1;
                ctx.putImageData(dataList[j],0,0);
                ctx.globalAlpha=1- fadeRate;
                ctx.fillStyle = "Black";
                ctx.fillRect(0,0,setting.width,setting.height);

                combineCtx.drawImage(cnvList[j].cnv,0,0);
            }

            //提取combineCnv的信息并储存
            resultList.push(combineCtx.getImageData(0,0,setting.width,setting.height));
        }
        Log("渲染结束");
        setTimeout(function (){
            // 在这里进行最终的合成_________________________________________________
            Record();
        },1000);
    }

    //录制渲染结果
    function Record(){
        Log("渲染结果开始录制");
        console.log(resultList);
        recorder.start();
        let timer = setInterval(function (){

            resultCtx.putImageData(resultList.shift(),0,0);
            if(resultList.length===0){
                Log("渲染结果录制结束");
                clearInterval(timer);
                recorder.stop();

            }
        },1000/setting.fps);
    }

    function DownLoad(blob){
        Log("开始下载文件："+setting.name+type);
        blob = new Blob(blob,blobOption);
        let url = URL.createObjectURL(blob);
        let link = document.createElement("a");
        link.href = url;
        link.download = setting.name+type;
        link.style.display = "none";
        document.body.appendChild(link);
        link.click();
        link.remove();
    }

    function OnClick(){
        Init();
        GetFrames();
    }

    function Show(element){
        if(setting && setting.debug){
            document.body.appendChild(element);
        }
    }

    function Log(msg){
        /*setTimeout(function (){
            message.innerHTML = msg;
        });*/
        msgString = msg;
        console.log(msg);
    }
</script>
</html>